package com.pivotal.cloud.crypto.utils;

import javax.crypto.*;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;

/**
 * @className: com.pivotal.cloud.security.utils.CipherUtil
 * @projectName: PivotalCloud项目
 * @module: PivotalCloud项目-CipherUtil类，主要位于Security安全模块-CipherUtil工具类模块
 * @content: CipherUtil-CipherUtil工具类
 * @author: Powered by Marklin
 * @datetime: 2025-06-25 22:52
 * @version: 1.0.0
 * @copyright: Copyright © 2018-2025 PivotalCloud Systems Incorporated. All rights
 * reserved.
 */
public final class CipherUtil {

	private CipherUtil() {
	}

	/**
	 * Generates a SecretKey.
	 */
	public static SecretKey newSecretKey(String algorithm, String password) {
		return newSecretKey(algorithm, new PBEKeySpec(password.toCharArray()));
	}

	/**
	 * Generates a SecretKey.
	 */
	public static SecretKey newSecretKey(String algorithm, PBEKeySpec keySpec) {
		try {
			SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm);
			return factory.generateSecret(keySpec);
		}
		catch (NoSuchAlgorithmException ex) {
			throw new IllegalArgumentException("Not a valid encryption algorithm", ex);
		}
		catch (InvalidKeySpecException ex) {
			throw new IllegalArgumentException("Not a valid secret key", ex);
		}
	}

	/**
	 * Constructs a new Cipher.
	 */
	public static Cipher newCipher(String algorithm) {
		try {
			return Cipher.getInstance(algorithm);
		}
		catch (NoSuchAlgorithmException ex) {
			throw new IllegalArgumentException("Not a valid encryption algorithm", ex);
		}
		catch (NoSuchPaddingException ex) {
			throw new IllegalStateException("Should not happen", ex);
		}
	}

	/**
	 * Initializes the Cipher for use.
	 */
	public static <T extends AlgorithmParameterSpec> T getParameterSpec(Cipher cipher, Class<T> parameterSpecClass) {
		try {
			return cipher.getParameters().getParameterSpec(parameterSpecClass);
		}
		catch (InvalidParameterSpecException ex) {
			throw new IllegalArgumentException("Unable to access parameter", ex);
		}
	}

	/**
	 * Initializes the Cipher for use.
	 */
	public static void initCipher(Cipher cipher, int mode, SecretKey secretKey) {
		initCipher(cipher, mode, secretKey, null);
	}

	/**
	 * Initializes the Cipher for use.
	 */
	public static void initCipher(Cipher cipher, int mode, SecretKey secretKey, byte[] salt, int iterationCount) {
		initCipher(cipher, mode, secretKey, new PBEParameterSpec(salt, iterationCount));
	}

	/**
	 * Initializes the Cipher for use.
	 */
	public static void initCipher(Cipher cipher, int mode, SecretKey secretKey, AlgorithmParameterSpec parameterSpec) {
		try {
			if (parameterSpec != null) {
				cipher.init(mode, secretKey, parameterSpec);
			}
			else {
				cipher.init(mode, secretKey);
			}
		}
		catch (InvalidKeyException ex) {
			throw new IllegalArgumentException("Unable to initialize due to invalid secret key", ex);
		}
		catch (InvalidAlgorithmParameterException ex) {
			throw new IllegalStateException("Unable to initialize due to invalid decryption parameter spec", ex);
		}
	}

	/**
	 * Invokes the Cipher to perform encryption or decryption (depending on the
	 * initialized mode).
	 */
	public static byte[] doFinal(Cipher cipher, byte[] input) {
		try {
			return cipher.doFinal(input);
		}
		catch (IllegalBlockSizeException ex) {
			throw new IllegalStateException("Unable to invoke Cipher due to illegal block size", ex);
		}
		catch (BadPaddingException ex) {
			throw new IllegalStateException("Unable to invoke Cipher due to bad padding", ex);
		}
	}

}
